<?php

use Phalcon\DI\FactoryDefault;
use Phalcon\Config;
use Phalcon\Session\Adapter\Files;
use Phalcon\Loader;
use Phalcon\Mvc\Url;
use Phalcon\Mvc\Router;
use Phalcon\Db\Adapter\Pdo\Mysql as PhMysql;
use Phalcon\Exception as PhException;
use Phalcon\Mvc\Application;
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Volt;
use Phalcon\Mvc\Model\Metadata\Memory as PhMetadataMemory;
use Phalcon\Cache\Frontend\Output as PhCacheFront;
use Phalcon\Cache\Backend\File as PhCacheBackFile;
use Phalcon\Cache\Backend\Apc as PhCacheBackApc;
use Phalcon\Db\Adapter\Pdo\Mysql as DbAdapter;

class Bootstrap {

    private $di;

    public function __construct() {
        $di       = new FactoryDefault();
        $this->di = $di;
    }

    public function run($options) {

        $loaders = array(
            'config',
            'loader',
            'view',
            'url',
            'database',
            'router',
            'dispatcher',
            'session',
            'cache',
//            'redis',
            'security',
            'crypt',
        );

        try {
            foreach ($loaders as $service) {
                $function = 'init' . ucfirst($service);
                $this->$function($options);
            }

            $application = new Application();
            $application->setDI($this->di);

            $this->di['app'] = $application;
            //$a =  APP_PATH . '/config/' . APP_ENV . '/modules.php';
            //echo $a;die();
            $application->registerModules(
                require APP_PATH . '/config/' . APP_ENV . '/modules.php'
            );
            //var_dump($application);die();
            return $application->handle()->getContent();
        } catch (PhException $e) {
            echo $e->getMessage();
        } catch (\PDOException $e) {
            echo $e->getMessage();
        }

        return false;
    }

    protected function initSession($options = array()) {
        $config              = $this->di['config'];
        //$this->di['session'] = function () use ($config) {
        //    $session = new \Phalcon\Session\Adapter\Redis(array(
        //        'uniqueId'   => 'my-private-app',
        //        'host'       => $config->redis->host,
        //        'port'       => $config->redis->port,
        //        'auth'       => $config->redis->auth,
        //        'persistent' => false,
        //        'lifetime'   => 43200,
        //        'prefix'     => $config->redis->prefix,
        //    ));
        //
        //    $session->start();
        //
        //    return $session;
        //};

        $this->di['session'] = function () {
            $session = new Files();
            $session->start();
            # 销毁缓存
            //$session->destroy();

            return $session;
        };
    }

    protected function initConfig($options = array()) {
        //$configFile         = require(APP_PATH . '/config/config.php');
        $configFile         = include_once APP_PATH . '/config/' . APP_ENV . '/config.php';
        $config             = new Config($configFile);
        $this->di['config'] = $config;
    }

    protected function initLoader($options = array()) {
        $config = $this->di['config'];

        $loader = new Loader();

        $loader->registerNamespaces([
            'Models'          => $config->application->modelsDir,
//            'Models\Officehall' => APP_PATH . '/apps/models/officehall',
//            'Models\Oa'         => APP_PATH . '/apps/models/oa',
//            'Models\Tzkt'         => APP_PATH . '/apps/models/tzkt',
//            'Models\Monitor'         => APP_PATH . '/apps/models/monitor',
            'Models\Api'         => APP_PATH . '/apps/models/api',
            'Models\Entities' => $config->application->modelsEntitiesDir,
            'Models\Services' => $config->application->modelsServicesDir,
            'Controllers'     => $config->application->controllersDir,
            'Plugins'         => $config->application->pluginsDir,
            'Lib'             => $config->application->libraryDir,
            'Forms'           => $config->application->formsDir,
        ]);

        $loader->register();
    }

    protected function initUrl($options = array()) {
        $config = $this->di['config'];

        $this->di->setShared('url', function () use ($config) {
            $url = new Url();
            $url->setBaseUri($config->application->baseUri);

            return $url;
        });
    }

    protected function initDispatcher() {
        $di = $this->di;

        $di->set('dispatcher', function () use ($di) {
            $eventsManager = $di->getShared('eventsManager');
            $noFound       = new \Plugins\NotFound($di);
            $eventsManager->attach('dispatch', $noFound); // not dispatcher
            $dispatcher = new \Phalcon\Mvc\Dispatcher();
            $dispatcher->setEventsManager($eventsManager);
            $dispatcher->setDefaultNamespace('\Modules\Admin\Controllers');

            return $dispatcher;
        });

    }

    protected function initRouter($options = array()) {
        $config = $this->di['config'];

        $this->di['router'] = function () use ($config) {
            $router     = new Router(false);
            $routerInfo = require APP_PATH . '/config/' . APP_ENV . '/routes.php';

            foreach ($routerInfo as $item) {
                $router->add($item[0], $item[1]);
            }

            //$router->setDefaultModule('admin');
            $router->setDefaultNamespace('Controllers');
            $router->removeExtraSlashes(true);
            $router->notFound(
                array(
                    'controller' => 'error',
                    'action'     => 'show404',
                )
            );

            return $router;
        };
    }

    protected function initDatabase($options = array()) {
        $config = $this->di['config'];

        $this->di->setShared('db', function () use ($config) {
            return new DbAdapter($config->database->toArray());
        });

        $this->di->setShared('monitor', function () use ($config) {
            return new DbAdapter($config->monitor->toArray());
        });
    }

    /**
     * Initializes the cache
     *
     * @param array $options
     */
    protected function initCache($options = array()) {
        $config = $this->di['config'];

        $this->di['cache'] = function () use ($config) {
            /*$frontCache = new \Phalcon\Cache\Frontend\Data(array(
                "lifetime" => 86400,
            ));*/

            $frontCache = new PhCacheFront(array('lifetime' => $config->cache->lifetime));

            if (function_exists('apc_store')) {
                $cache = new PhCacheBackApc($frontCache);
            } else {
                $backEndOptions = array('cacheDir' => $config->cache->cacheDir);
                $cache          = new PhCacheBackFile($frontCache, $backEndOptions);
            }

            // redis config
            /*$cache = new Phalcon\Cache\Backend\Redis($frontCache, array(
                'host'       => $config->redis->host,
                'port'       => $config->redis->port,
                'auth'       => $config->redis->auth,
                'persistent' => false,
                'prefix'     => $config->redis->prefix,
            ));*/

            return $cache;
        };
    }

//    protected function initRedis($options = array()) {
//        $config = $this->di['config'];
//
//        if (!extension_loaded('redis')) {
//            throw new \Exception('Redis is need redis Extension!');
//        }
//
//        $this->di->setShared('redis', function () use ($config) {
//            $host   = $config->redis->host;
//            $port   = $config->redis->port;
//            $auth   = $config->redis->auth;
//            $db     = $config->redis->db;
//            $prefix = $config->redis->prefix;
//
//            $redis = new \Redis();
//
//            if (!!$port) {
//                $status = $redis->pconnect($host, $port, 3);
//            } else {
//                $status = $redis->pconnect($host);
//            }
//
//            if (!$status) {
//                throw new \Exception('Unable to connect to the redis:' . $host);
//            }
//
//            if ($auth) {
//                $redis->auth($auth);
//            }
//
//            if ($db) {
//                $redis->select($db);
//            }
//
//            if ($prefix) {
//                $redis->setOption(\Redis::OPT_PREFIX, $prefix);
//            }
//
//            return $redis;
//        });
//    }

    protected function initView($options = array()) {
        $config = $this->di['config'];
        $di     = $this->di;

        $this->di['view'] = function () use ($config, $di) {
            $view = new View();
            //$view->setViewsDir(APP_PATH . '/apps/modules/admin/views');
            $view->setViewsDir(APP_PATH . '/apps/views');

            return $view;
        };
    }

    protected function initSecurity($options = []) {
//        $this->di['security'] = function () {
//            $security = new \Phalcon\Security();
//
//            // Set the password hashing factor to 12 rounds
//            $security->setWorkFactor(12);
//
//            return $security;
//        };
    }

    protected function initCrypt($options = []) {
        $this->di['crypt'] = function () {
            $crypt = new Phalcon\Crypt();
            // 设置全局加密密钥
            $crypt->setKey(
                "%31.1e&i46e@f!8jz"
            );

            return $crypt;
        };
    }


}
